package com.jmemoir.authorize.security.utils;

import com.jmemoir.authorize.security.entity.User;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;

import java.util.Collection;
import java.util.List;

/**
 * Spring Security 工具类
 *
 * @author Tellsea
 * @date 2023/8/8
 */
public class SecurityUtils {

    private static final PasswordEncoder passwordEncoder = new BCryptPasswordEncoder();

    public static User getCurrentUser() {
        Authentication authentication = getAuthentication();
        if (authentication != null && authentication.isAuthenticated()) {
            Object principal = authentication.getPrincipal();
            if (principal instanceof User) {
                return (User) principal;
            }
        }
        return null;
    }

    public static boolean isAuthenticated() {
        Authentication authentication = getAuthentication();
        return authentication != null && authentication.isAuthenticated();
    }

    public static boolean hasRole(String role) {
        Authentication authentication = getAuthentication();
        if (authentication != null && authentication.isAuthenticated()) {
            Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities();
            for (GrantedAuthority authority : authorities) {
                if (authority.getAuthority().equals(role)) {
                    return true;
                }
            }
        }
        return false;
    }

    public static boolean hasAllRoles(List<String> roles) {
        Authentication authentication = getAuthentication();
        if (authentication != null && authentication.isAuthenticated()) {
            Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities();
            for (String role : roles) {
                boolean hasRole = authorities.stream()
                        .anyMatch(authority -> authority.getAuthority().equals(role));
                if (!hasRole) {
                    return false;
                }
            }
            return true;
        }
        return false;
    }

    public static boolean hasAnyRole(List<String> roles) {
        Authentication authentication = getAuthentication();
        if (authentication != null && authentication.isAuthenticated()) {
            Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities();
            for (String role : roles) {
                boolean hasRole = authorities.stream()
                        .anyMatch(authority -> authority.getAuthority().equals(role));
                if (hasRole) {
                    return true;
                }
            }
        }
        return false;
    }

    public static boolean hasPermission(String permission) {
        Authentication authentication = getAuthentication();
        if (authentication != null && authentication.isAuthenticated()) {
            Object principal = authentication.getPrincipal();
            if (principal instanceof UserDetails) {
                UserDetails userDetails = (UserDetails) principal;
                return userDetails.getAuthorities().stream()
                        .anyMatch(authority -> authority.getAuthority().equals(permission));
            }
        }
        return false;
    }

    public static boolean hasAllPermissions(List<String> permissions) {
        Authentication authentication = getAuthentication();
        if (authentication != null && authentication.isAuthenticated()) {
            Object principal = authentication.getPrincipal();
            if (principal instanceof UserDetails) {
                UserDetails userDetails = (UserDetails) principal;
                Collection<? extends GrantedAuthority> authorities = userDetails.getAuthorities();
                for (String permission : permissions) {
                    boolean hasPermission = authorities.stream()
                            .anyMatch(authority -> authority.getAuthority().equals(permission));
                    if (!hasPermission) {
                        return false;
                    }
                }
                return true;
            }
        }
        return false;
    }

    public static boolean hasAnyPermission(List<String> permissions) {
        Authentication authentication = getAuthentication();
        if (authentication != null && authentication.isAuthenticated()) {
            Object principal = authentication.getPrincipal();
            if (principal instanceof UserDetails) {
                UserDetails userDetails = (UserDetails) principal;
                Collection<? extends GrantedAuthority> authorities = userDetails.getAuthorities();
                for (String permission : permissions) {
                    boolean hasPermission = authorities.stream()
                            .anyMatch(authority -> authority.getAuthority().equals(permission));
                    if (hasPermission) {
                        return true;
                    }
                }
            }
        }
        return false;
    }

    public static Authentication getAuthentication() {
        return SecurityContextHolder.getContext().getAuthentication();
    }

    public static void setAuthentication(Authentication authentication) {
        SecurityContextHolder.getContext().setAuthentication(authentication);
    }

    public static String encodePassword(String password) {
        return passwordEncoder.encode(password);
    }

    public static boolean matchPassword(String rawPassword, String encodedPassword) {
        return passwordEncoder.matches(rawPassword, encodedPassword);
    }
}